<?php

/*
 *  This file is part of MetaMVC.
 * 
 *  MetaMVC is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  MetaMVC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with MetaMVC.  If not, see <http://www.gnu.org/licenses/>.
 */
namespace MetaMVC\Framework;

use MetaMVC\Framework\Routing;
/**
 * This class is the main entry point for MetaMVC, and is responsible for
 * handleing the incoming request.
 *
 * @author artzter
 * @package MetaMVC
 * @copyright (c) 2013, Dennis Nielsen
 */
class Application {
    protected $appPath;
    protected $config;
    /**
     * Contains the current request.
     * @var Request
     */
    protected $request;
    protected $areas;
    protected $controller;


    public function __construct($path) {
        $this->appPath = $path;
    }
    
    public function loadConfiguration($path) {
        $this->config = parse_ini_file($path, true);
    }

    public function run() {
        $this->generateRequest();
        $this->handleRequest();
    }
    
    private function generateRequest() {
        $requestArray = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
        
        // Checking if area is defined
        if(in_array($requestArray[0], $this->config["areas"])) {
            $area = $requestArray[0];
        } else {
            $area = null;
        }
        
        // Loads the routes and generates the request.
        require "$this->appPath/routes.php";        
        $this->request = Routing\RoutingTable::findMatch($requestArray, $area, $this->config["routing"]);
    }
    
    private function handleRequest() {
        /* =======================================================
         *                  CONTROLLER VALIDATION
           ======================================================= */
        // Checks the existance
        $controllerPath = "$this->appPath/Controllers/";
        
        if($this->request->getArea() != null)
            $controllerPath .= ucfirst(strtolower ($this->request->getArea())) . "Area/";
        
        $controllerName = ucfirst(strtolower($this->request->getController())) . "Controller";
        $realPath = realpath($controllerPath . $controllerName . '.php');
        
        if(!file_exists($realPath) || !is_file($realPath))
            throw new \Exception ("The requested controller \"$controllerName\" could not be found.");
            
        // Loads the controller
        require_once $realPath;
        $this->controller = new $controllerName();
        
        
        /* =======================================================
         *                  ACTION VALIDATION
           ======================================================= */
        // Checks the existance
        $actionName = ucfirst(strtolower($this->request->getAction())) . "Action";
        
        if(!method_exists($this->controller, $actionName))
            throw new \Exception("Unable to find the requested action \"$actionName\" in \"$controllerName\"");
        
        // Checks the argument count
        $actionReflection = new \ReflectionMethod($this->controller, $actionName);
        $actionReqArgCount = $actionReflection->getNumberOfRequiredParameters();
        $actionTotalArgCount = $actionReflection->getNumberOfParameters();
        $requestArgCount = count($this->request->getArgs());
        
        if($requestArgCount > $actionTotalArgCount)
            throw new \Exception("$actionName in $controllerName recieved $requestArgCount arguments, but handles $actionTotalArgCount at max.");
        
        if($requestArgCount < $actionReqArgCount)
            throw new \Exception("$actionName in $controllerName requires at least $actionReqArgCount arguments, but only $requestArgCount recieved.");

        /* =======================================================
         *                      EXECUTION
           ======================================================= */
        // Pre execution
        if(method_exists($this->controller, 'PreExec'))
            $this->controller->PreExec();
        
        // Action execution
        $actionReflection->invokeArgs($this->controller, $this->request->getArgs());
        
        // Post execution
        if(method_exists($this->controller, 'PostExec'))
            $this->controller->PostExec();
        
        
    }
}

?>